# -*- coding: utf-8 -*-

import random
from typing import Optional

import requests
from faker import Faker

from utils import tools
from utils.db.redisdb import RedisDB
from utils.logs import log
from utils.proxies_tools import get_company_ip_crawler_by_api
from utils.user_pool.base_user_pool import UserPoolInterface, GuestUser


class GuestUserPool(UserPoolInterface):
    """
    访客用户池 不需要登陆
    """
    session = requests.Session()

    def __init__(
            self,
            redis_key,
            page_url=None,
            min_users=1,
            must_contained_keys=(),
            keep_alive=False,
            redis_kwargs=None,
            **kwargs,
    ):
        """
        @param redis_key: user存放在redis中的key前缀
        @param page_url: 生产user的url
        @param min_users: 最小user数
        @param must_contained_keys: cookie中必须包含的key，用于校验cookie是否正确
        @param keep_alive: 是否保持常驻，以便user不足时立即补充
        ---
        @param kwargs: RedisDB的一些参数
        """

        if redis_kwargs is None:
            redis_kwargs = {}
        self._redisdb = RedisDB(**redis_kwargs)

        self._tab_user_pool = "scrapy:user_pool:{redis_key}:h_{user_type}_pool".format(
            redis_key=redis_key, user_type="guest"
        )
        self._page_url = page_url
        self._min_users = min_users
        self._must_contained_keys = must_contained_keys
        self._keep_alive = keep_alive

        self._users_id = []

    def _load_users_id(self):
        self._users_id = self._redisdb.hkeys(self._tab_user_pool)
        if self._users_id:
            random.shuffle(self._users_id)

    def _get_user_id(self):
        if not self._users_id:
            self._load_users_id()

        if self._users_id:
            return self._users_id.pop()

    def login(self) -> Optional[GuestUser]:
        """
        默认去登录，生产cookie，可以重写
        """
        user_agent = Faker().user_agent()
        self.session.headers.update({"User-Agent": user_agent})
        proxies = get_company_ip_crawler_by_api()
        self.session.proxies = proxies
        self.session.get(self._page_url, timeout=10)
        cookies = self.session.cookies.get_dict()
        for key in self._must_contained_keys:
            if key not in cookies:
                break
        else:
            user = GuestUser(user_agent=user_agent, cookies=cookies, proxies=proxies)
            return user

        log.error("获取cookie失败 cookies = {}".format(cookies))
        return None

    def add_user(self, user: GuestUser):
        log.debug("add {}".format(user))
        self._redisdb.hset(self._tab_user_pool, user.user_id, user.to_dict())

    def get_user(self, block=True) -> Optional[GuestUser]:
        """

        Args:
            block: 无用户时是否等待

        Returns:

        """
        while True:
            try:
                user_id = self._get_user_id()
                user_str = None
                if user_id:
                    user_str = self._redisdb.hget(self._tab_user_pool, user_id)
                    # 如果没取到user，可能是其他爬虫将此用户删除了，需要重刷新本地缓存的用户id
                    if not user_str:
                        self._load_users_id()
                        continue

                if not user_id and block:
                    self._keep_alive = False
                    self._min_users = 1
                    self.run()
                    continue

                return user_str and GuestUser(**eval(user_str))
            except Exception as e:
                log.exception(e)
                tools.delay_time(1)

    def del_user(self, user_id: str):
        log.debug("del {}".format(user_id))
        self._redisdb.hdel(self._tab_user_pool, user_id)
        self._load_users_id()

    def run(self):
        while True:
            try:
                now_user_count = self._redisdb.hget_count(self._tab_user_pool)
                need_user_count = self._min_users - now_user_count

                if need_user_count > 0:
                    log.info(
                        "当前在线user数为 {} 小于 {}, 生产user".format(
                            now_user_count, self._min_users
                        )
                    )
                    try:
                        user = self.login()
                        if user:
                            self.add_user(user)
                    except Exception as e:
                        log.exception(e)
                else:
                    log.debug("当前user数为 {} 数量足够 暂不生产".format(now_user_count))

                    if self._keep_alive:
                        tools.delay_time(10)
                    else:
                        break

            except Exception as e:
                log.exception(e)
                tools.delay_time(1)
